var Clickoutside = function () {
  var nodeList = [];
  var ctx = '@@clickoutsideContext';

  var startClick;
  var seed = 0;

  $(document).on('mousedown', function (e) {
    startClick = e;
  });

  $(document).on('mouseup', function (e) {
    for (var i = 0; i < nodeList.length; i++) {
      var node = nodeList[i];
      node[ctx].documentHandler(e, startClick)
    }
  });

  function createDocumentHandler(el, binding, vnode) {
    return function (mouseup, mousedown) {
      if (mouseup === undefined) {
        mouseup = {};
      }
      if (mousedown === undefined) {
        mousedown = {};
      }
      if (!vnode ||
        !vnode.context ||
        !mouseup.target ||
        !mousedown.target ||
        el.contains(mouseup.target) ||
        el.contains(mousedown.target) ||
        el === mouseup.target ||
        (vnode.context.popperElm &&
          (vnode.context.popperElm.contains(mouseup.target) ||
            vnode.context.popperElm.contains(mousedown.target)))) return;

      if (binding.expression &&
        el[ctx].methodName &&
        vnode.context[el[ctx].methodName]) {
        vnode.context[el[ctx].methodName](startClick);
      } else {
        el[ctx].bindingFn && el[ctx].bindingFn(startClick);
      }
    };
  }

  return {
    bind(el, binding, vnode) {
      nodeList.push(el);
      var id = seed++;
      el[ctx] = {
        id,
        documentHandler: createDocumentHandler(el, binding, vnode),
        methodName: binding.expression,
        bindingFn: binding.value
      };
    },

    update(el, binding, vnode) {
      el[ctx].documentHandler = createDocumentHandler(el, binding, vnode);
      el[ctx].methodName = binding.expression;
      el[ctx].bindingFn = binding.value;
    },

    unbind(el) {
      var len = nodeList.length;

      for (var i = 0; i < len; i++) {
        if (nodeList[i][ctx].id === el[ctx].id) {
          nodeList.splice(i, 1);
          break;
        }
      }
      delete el[ctx];
    }
  };
}();

var SysCommonSearch = function () {
  var dropdownDictionary = {
    materialName: "物料名称",
    materialType: "物料类型",
    machining: "加工对象",
    model: "规格型号",
    color: "编号",
    colorDescription: "描述",
    providerName: "供应商",
    factoryNo: "工厂型号",
    factoryId: "工厂型号",
    orderId: "系统订单编号",
    companyOrderId: "订单编号",
    customerNo: "客户型号",
    coustomId: "客户型号",
    customerId: "客户型号",
    coustomOrderId: "客户订单号",
    customerOrderId: "客户订单号",
    customer: "客户",
    providerNo: "供方编号",
    materialDept: "物料部门",
    outOrderDept: "订单部门",
    orderDept: "部门"
  };

  var selectDefaultDropdownOption = {
    materialDept: {
      valueField: "materialDeptId",
      labelField: "materialDeptName"
    },
    outOrderDept: {
      valueField: "deptId",
      labelField: "deptName"
    },
    orderDept: {
      valueField: "deptId",
      labelField: "deptName"
    },
    bank: {
      valueField: "bank",
      labelField: "bank"
    }
  };

  var getParentEl = function (el, className) {
    var $el = $(el);
    if ($el.hasClass(className)) {
      return $el;
    }

    $el = $el.parents('.' + className);
    if ($el.length === 0) {
      return null;
    }
    return $el;
  };

  var PageAutocomplete = function () {
    var template = /* html */ `
      <div class="page-autocomplete">
        <el-popover v-clickoutside="hidePopovere" v-model="isShow" placement="bottom-start" trigger="manual" popper-class="page-autocomplete-popover">
          <el-input slot="reference" v-model="showValue" :size="size" :placeholder="placeholder" @click.native="inputClick" @input="checkData" @change="handleChange"></el-input>
          <el-scrollbar ref="scrollbar" :key="'scrollbar_'+showOptions.length">
            <div class="popover-content" :class="{'has-page':totalPage>1}" :style="{'min-width':popoverWidth+'px'}" v-loading.lock="loading">
              <div class="popover-content-list">
                <div v-for="(option,index) in showOptions" :key="'item_'+index" class="popover-content-item" @click="itemClick(option)">{{option}}</div>
              </div>
            </div>
          </el-scrollbar>
          <div v-if="totalPage>1" ref="page" class="popover-page clearfix">
            <div v-if="currentPage>1" style="float:left" @click="pageChange('previous')">上一页</div>
            <div v-if="currentPage<totalPage" style="float:right" @click="pageChange('next')">下一页</div>
          </div>
        </el-popover>
      </div>
    `;

    return {
      props: {
        value: {
          required: true
        },
        placeholder: {
          type: String,
          required: true
        },
        valueKey: {
          type: String,
          default: 'value'
        },
        pageSize: {
          type: Number,
          default: 100
        },
        fetchSuggestions: Function,
        size: String
      },

      directives: {
        Clickoutside: Clickoutside
      },

      watch: {
        value: function () {
          if (this.inputValue !== null) {
            this.inputValue = null;
            return;
          }
          this.showValue = this.value;
        }
      },

      computed: {
        totalPage: function () {
          var pagination = this.pagination;
          var pageCount = pagination.totalCount / pagination.pageSize;
          pageCount = Math.ceil(pageCount);
          return pageCount;
        },

        currentPage: function () {
          return this.pagination.currentPage;
        }
      },

      data: function () {
        return {
          loading: false,
          isShow: false,
          popoverWidth: 0,
          showValue: this.value,
          inputValue: null,
          timeout: null,
          options: [],
          showOptions: [],
          pagination: {
            currentPage: 1,
            totalCount: 0,
            pageSize: this.pageSize
          }
        };
      },

      mounted: function () {
        var width = $(this.$el).width();
        this.popoverWidth = width - 2;
      },

      methods: {
        inputClick: function () {
          if (this.isShow) {
            return;
          }

          this.checkData();
          if (this.isShow) {
            this.resetScroll();
          }
        },

        itemClick: function (value) {
          if (this.value === value) {
            return;
          }

          this.clearTimeout();
          this.showValue = value;
          this.inputValue = value;
          this.$emit('input', value);
          this.$emit('change', value);
        },

        handleChange: function () {
          var self = this;
          var showValue = this.showValue;
          this.timeout = window.setTimeout(function () {
            self.inputValue = showValue;
            self.$emit('input', showValue);
            self.$emit('change', showValue);
            self.timeout = null;
          }, 50);
        },

        hidePopovere: function (clickEvent) {
          var $page = this.$refs['page'];
          if ($page !== undefined) {
            var $target = getParentEl(clickEvent.target, 'popover-page');
            if ($target !== null && $target.is($page)) {
              return;
            }
          }
          this.isShow = false;
        },

        checkData: function () {
          var queryValue = this.showValue;
          var fetchSuggestions = this.fetchSuggestions;
          this.loading = true;

          var self = this;
          fetchSuggestions(queryValue, function (options) {
            self.setSuggestions(options);
          });
        },

        setSuggestions: function (options) {
          this.loading = false;
          var valueKey = this.valueKey;
          options = _.map(options, valueKey);
          this.options = options;
          this.pagination.totalCount = options.length;
          this.pagination.currentPage = 1;
          this.toPageData();
          if (options.length === 0) {
            this.isShow = false;
          } else {
            this.isShow = true;
          }
        },

        toPageData: function () {
          var pagination = this.pagination;
          var pageSize = pagination.pageSize;
          var startIndex = (pagination.currentPage - 1) * pageSize;

          var options = this.options;
          options = options.slice(startIndex, startIndex + pageSize);
          this.showOptions = options;
        },

        pageChange: function (type) {
          var currentPage = this.currentPage;
          if (type === 'previous') {
            currentPage--;
          } else if (type === 'next') {
            currentPage++;
          }
          this.pagination.currentPage = currentPage;
          this.toPageData();
          this.resetScroll();

          var self = this;
          this.$nextTick(function () {
            var scrollbar = self.$refs['scrollbar'];
            $(scrollbar.$el).find('.el-scrollbar__wrap').scrollTop(0);
          });
        },

        clearSuggestions: function () {
          this.options = [];
          this.showOptions = [];
        },

        resetScroll: function () {
          var self = this;
          this.$nextTick(function () {
            self.$refs['scrollbar'].moveY = 0;
          });
        },

        clearTimeout: function () {
          var timeout = this.timeout;
          if (timeout !== null) {
            window.clearTimeout(timeout);
            this.timeout = null;
          }
        }
      },

      template: template
    };
  }();

  var optionFilter = function (obj, search, searchField, itemField) {
    for (var i = 0; i < searchField.length; i++) {
      var fieldObj = searchField[i];
      var field = fieldObj.field;
      if (field === itemField) {
        continue;
      }

      var type = fieldObj.type;
      var searchValue = search[fieldObj.field];
      if (SysUtil.isEmpty(searchValue)) {
        continue;
      }

      if (type === 'select') {
        field = fieldObj.valueField;
      }
      var value = obj[field];
      if (SysUtil.isEmpty(value)) {
        return false;
      }
      if (type === 'select') {
        searchValue = searchValue[field];
        if (value !== searchValue) {
          return false;
        }
      } else {
        if (value.trim() === '') {
          return false;
        }
        value = _.toLower(value);
        searchValue = _.toLower(searchValue);
        if (value.indexOf(searchValue) === -1) {
          return false;
        }
      }
    }
    return true;
  };

  var SearchSelect = function () {
    var template = /* html */ `
      <el-select clearable filterable v-model="search[item.field]" @visible-change="selectVisibleChange" :value-key="item.valueField" :loading="loading"
        @change="handleChange">
        <template v-if="hasShowDropdown">
          <el-option v-for="showOption in options" :key="'item_'+showOption[item.valueField]" :value="showOption" :label="showOption[item.labelField]">
          </el-option>
        </template>
        <template v-else>
          <el-option v-if="search[item.field]!==''" :value="search[item.field]" :label="search[item.field][item.labelField]"></el-option>
        </template>
      </el-select>
    `;

    return {
      props: {
        search: {
          type: Object,
          required: true
        },
        searchField: {
          type: Array,
          required: true
        },
        item: {
          type: Object,
          required: true
        },
        dropdownData: {
          type: Array,
          default: function () {
            return [];
          }
        }
      },
      watch: {
        search: {
          handler: function (newSearch) {
            var fields = _.map(this.searchField, 'field');
            var itemField = this.item.field;
            _.remove(fields, function (field) {
              return itemField === field;
            });
            if (SysUtil.equalsObj(this.oldSearch, newSearch, fields)) {
              return;
            }
            this.oldSearch = _.cloneDeep(newSearch);
            this.options = null;
          },
          deep: true
        },
        dropdownData: function () {
          if (this.search[this.item.field]) {
            return;
          }
          this.initOption();
          this.setOptions();
        }
      },
      data: function () {
        var search = this.search;
        return {
          oldSearch: _.cloneDeep(search),
          loading: false,
          hasShowDropdown: false,
          optionDropdownData: [],
          optionDropdownGroup: null,
          options: null
        };
      },
      created: function () {
        this.initOption();
        if (!SysUtil.isEmpty(this.search[this.item.field])) {
          this.setOptions();
        }
      },
      methods: {
        initOption: function () {
          var item = this.item;
          var dropdownData = this.dropdownData;
          var optionDropdownData = _.filter(dropdownData, function (obj) {
            var value = obj[item.valueField];
            var label = obj[item.labelField];
            return !SysUtil.isEmpty(value) && !SysUtil.isEmpty(label);
          });
          this.optionDropdownData = optionDropdownData;
          this.optionDropdownGroup = _.groupBy(optionDropdownData, item.valueField);
        },

        setOptions: function () {
          this.options = this.getOptions();
        },

        getOptions: function () {
          var search = this.search;
          var searchField = this.searchField;
          var optionDropdownData = this.optionDropdownData;
          var item = this.item;
          var options = [];
          for (var i = 0; i < optionDropdownData.length; i++) {
            var obj = optionDropdownData[i];
            if (optionFilter(obj, search, searchField, item.field)) {
              var option = {};
              option[item.valueField] = obj[item.valueField];
              option[item.labelField] = obj[item.labelField];
              options.push(option);
            }
          }
          options = _.uniqBy(options, item.valueField);
          return options;
        },

        filterOption: function () {
          this.loading = true;
          var self = this;
          new Promise(function (resole) {
            if (self.options === null) {
              self.setOptions();
            }
            self.loading = false;
            resole();
          });
        },

        selectVisibleChange: function (isShow) {
          this.hasShowDropdown = isShow;
          if (isShow) {
            this.filterOption();
          }
        },

        resetSelectValue: function () {
          var search = this.search;
          var itemField = this.item.field;
          var searchValue = search[itemField];
          if (searchValue === '') {
            return;
          }

          var optionDropdownGroup = this.optionDropdownGroup;
          var item = this.item;
          var value = _.get(search, `${item.field}.${item.valueField}`);
          var optionDropdownData;
          if (SysUtil.isEmpty(value)) {
            optionDropdownData = [];
          } else {
            optionDropdownData = optionDropdownGroup[value];
          }

          var self = this;
          var option = _.find(optionDropdownData, function (obj) {
            return optionFilter(obj, search, self.searchField, itemField);
          });
          if (option === undefined) {
            search[itemField] = '';
          }
        },

        getFilterData: function () {
          return this.getOptions();
        },

        handleChange: function () {
          this.$emit('change', this.search[this.item.field]);
        }
      },
      template: template
    };
  }();

  var template = /*html*/ `
    <el-form class="sys-common-search clearfix" :inline="inline" :label-width="labelWidth" :model="search" :size="size" v-loading.fullscreen.lock="loading">
      <slot name="prepend"></slot>
      <template v-for="item in formSearchField">
        <el-form-item :key="item.field" :label="dropdownDictionary[item.field]">
          <page-autocomplete v-if="item.type==='autocomplete'":ref="'input_'+item.field" class="search-input" v-model="search[item.field]" :value-key="item.field" :placeholder="'请输入'+dropdownDictionary[item.field]"
            :fetch-suggestions="function(){inputSuggestFun(item,arguments)}" :style="{width:inputWidth}" @change="autocompleteChange(item)"></page-autocomplete>
          <search-select v-else-if="item.type==='select'" :ref="'input_'+item.field" :search="search" :search-field="formSearchField" :item="item" :style="{width:inputWidth}" :dropdown-data="dropdownData" @change="selectChange(item)"></search-select>
        </el-form-item>
      </template>
      <slot name="append"></slot>
    </el-form>
  `;

  return {
    inject: {
      btnView: {
        default: null
      }
    },
    props: {
      search: {
        type: Object,
        required: true
      },
      requestUrl: {
        type: String,
        default: ''
      },
      requestData: {
        type: Object,
        default: function () {
          return {};
        }
      },
      labelWidth: {
        type: String,
        default: undefined
      },
      inputWidth: {
        type: String,
        default: undefined
      },
      responseFilterFun: {
        type: Function,
        default: undefined
      },
      inline: {
        type: Boolean,
        default: true
      },
      size: String,
      dropdownProps: Object,
      selectDropdownOptionConfig:Object,
      searchField: {
        type: Array,
        default: function () {
          return [];
        }
      }
    },
    data: function () {
      var dropdownProps = this.dropdownProps;
      var dropdown = _.cloneDeep(dropdownDictionary);
      if (dropdownProps !== undefined) {
        dropdown = _.assignIn(dropdown, dropdownProps);
      }
      var dataObj = {
        loading: false,
        dropdownData: [],
        dropdownDictionary: dropdown,
      };

      var formSearchField = [];
      var searchField = this.searchField;
      var selectDropdownOption = _.cloneDeep(selectDefaultDropdownOption);
      if (this.selectDropdownOptionConfig !== undefined) {
        _.assignIn(selectDropdownOption, this.selectDropdownOptionConfig);
      }
      dataObj.selectDropdownOption = selectDropdownOption;

      for (var i = 0; i < searchField.length; i++) {
        var field = searchField[i];
        var obj = {
          field: field
        };
        var option = selectDropdownOption[field];
        var type;
        if (option !== undefined) {
          _.assign(obj, option);
          type = "select";
        } else {
          type = "autocomplete";
        }
        obj.type = type;
        formSearchField.push(obj);

        if (type !== 'select') {
          dataObj[`${field}List`] = null;
        }
      }
      dataObj.formSearchField = formSearchField;
      return dataObj;
    },
    created: function () {
      this.setDropdownData();
    },
    methods: {
      setDropdownData: function () {
        var responseFilterFun = this.responseFilterFun;
        var url = this.requestUrl;
        var self = this;
        if (url === '') {
          if (responseFilterFun !== undefined) {
            return responseFilterFun().then(function (dropdownData) {
              self.setFormatDropdown(dropdownData);
              return true;
            }).catch(function () {
              return false;
            });
          }
          return Promise.resolve(false);
        }
        var postData = this.requestData;
        this.loading = true;
        return ajaxRequest(url, postData).then(function (dropdownData) {
          if (responseFilterFun !== undefined) {
            dropdownData = responseFilterFun(dropdownData);
          }

          self.setFormatDropdown(dropdownData);
          self.loading = false;
          return true;
        }).catch(function () {
          self.loading = false;
          return false;
        });
      },
      setFormatDropdown: function (dropdownData) {
        var self = this;
        var formSearchField = this.formSearchField;
        dropdownData = _.filter(dropdownData, function (obj) {
          var flag = false;
          for (var i = 0; i < formSearchField.length; i++) {
            var searchField = formSearchField[i];
            var field = searchField.field;
            var value;
            if (searchField.type === 'select') {
              value = obj[searchField.labelField];
              if (value !== '') {
                value = obj[searchField.valueField];
              }
            } else {
              value = obj[field];
            }

            if (value === null || value === undefined) {
              value = '';
            }

            if (typeof value === 'string') {
              value = value.trim();
              obj[field] = value;
            }
            if (flag) {
              continue;
            }
            if (!SysUtil.isEmpty(value)) {
              flag = true;
            }
          }
          return flag;
        });

        dropdownData = _.uniqBy(dropdownData, function (obj) {
          var values = [];
          for (var i = 0; i < formSearchField.length; i++) {
            var searchField = formSearchField[i];
            var field = searchField.field;
            var value;
            if (searchField.type === 'select') {
              value = obj[searchField.labelField];
              if (value !== '') {
                value = obj[searchField.valueField];
              }
            } else {
              value = obj[field];
            }
            values.push(value);
          }
          return values.join('$#$');
        });

        this.dropdownData = dropdownData;

        this.initSearchData().then(function (flag) {
          if (flag) {
            self.btnView.searchClick();
          }
        });
      },
      resetDropdownData() {
        var self = this;
        this.setDropdownData().then(function (flag) {
          if (flag) {
            var formSearchField = self.formSearchField;
            for (var i = 0; i < formSearchField.length; i++) {
              var f = formSearchField[i].field;
              if (formSearchField[i].type === 'select') {
                continue;
              }
              self[`${f}List`] = null;
            }
            self.clearSuggestions();
          }
        });
      },
      initSearchData() {
        var btnView = this.btnView;
        if (btnView === null) {
          return Promise.resolve(false);
        }

        if (!btnView.immediate || !btnView.isShowForm) {
          return Promise.resolve(false);
        }

        var search = this.search;
        if (search.materialDept === undefined) {
          return Promise.resolve(false);
        }

        var self = this;
        return SysUtil.getUser().then(function (user) {
          var isSelectionDept = user.companyInfo.isSelectionDept;
          if (isSelectionDept === undefined || isSelectionDept === 0) {
            return true;
          }

          var deptId = user.deptId;
          deptId = SysUtil.isEmpty(deptId) ? '' : Number(deptId);
          deptId = deptId === 0 ? '' : deptId;
          if (deptId === '') {
            return true;
          }

          var dropdownData = self.dropdownData;
          var data = _.find(dropdownData, {
            materialDeptId: deptId
          });
          if (data !== undefined) {
            search.materialDept = {
              materialDeptId: deptId,
              materialDeptName: data.materialDeptName
            };
          }
          return true;
        });
      },
      inputSuggestFun: function (item, arr) {
        var field = item.field;
        var queryValue = arr[0];
        var cb = arr[1];
        var dropdownList = this.getFilterData(field, queryValue);
        cb(dropdownList);
      },
      autocompleteChange: function (item) {
        this.searchChange(item);

        var formSearchField = this.formSearchField;
        for (var i = 0; i < formSearchField.length; i++) {
          var searchField = formSearchField[i];
          if (searchField.type === 'select') {
            this.$refs[`input_${searchField.field}`][0].resetSelectValue();
          }
        }
      },
      selectChange: function (item) {
        this.searchChange(item);
      },
      searchChange: function (item) {
        var field = item.field;
        var formSearchField = this.formSearchField;
        for (var i = 0; i < formSearchField.length; i++) {
          var searchField = formSearchField[i];
          if (searchField.type === 'select') {
            continue;
          }
          var f = searchField.field;
          if (f === field) {
            continue;
          }
          this[`${f}List`] = null;
        }
        this.clearSuggestions();
      },
      clearList: function () {
        var formSearchField = this.formSearchField;
        for (var i = 0; i < formSearchField.length; i++) {
          var searchField = formSearchField[i];
          if (searchField.type === 'autocomplete') {
            var field = searchField.field;
            this[`${field}List`] = null;
          }
        }
        this.clearSuggestions();
      },
      clearSuggestions: function () {
        var formSearchField = this.formSearchField;
        for (var i = 0; i < formSearchField.length; i++) {
          var searchField = formSearchField[i];
          if (searchField.type === 'select') {
            continue;
          }
          var field = searchField.field;
          var list = this[`${field}List`];
          if (list === null) {
            this.$refs[`input_${field}`][0].clearSuggestions();
          }
        }
      },
      getFilterData: function (field, queryValue) {
        var search = this.search;
        var formSearchField = this.formSearchField;
        var dropdownData = this.dropdownData;
        var dropdownList = this[`${field}List`];
        if (dropdownList === null) {
          dropdownList = _.filter(dropdownData, function (obj) {
            return optionFilter(obj, search, formSearchField, field);
          });
          dropdownList = _.uniqBy(dropdownList, field);
          this[`${field}List`] = dropdownList;
        }

        if (queryValue !== '') {
          queryValue = _.toLower(queryValue);
          dropdownList = _.filter(dropdownList, function (obj) {
            var value = obj[field];
            if (value === null || value === undefined) {
              value = '';
            }
            if (value === '' || value.trim() === '') {
              return false;
            }
            value = _.toLower(value);
            return value.indexOf(queryValue) !== -1;
          });
        } else {
          dropdownList = _.filter(dropdownList, function (obj) {
            var value = obj[field];
            if (value === null || value === undefined) {
              value = '';
            }
            value = value.trim();
            return value !== '';
          });
        }
        return dropdownList;
      },
      getFieldFilterData: function (field) {
        var search = this.search;
        var queryValue = search[field];
        var selectOption = this.selectDropdownOption[field];
        if (selectOption === undefined) {
          var dropdownList = this.getFilterData(field, queryValue);
          var filterData = _.map(dropdownList, field);
          return filterData;
        }

        return this.$refs[`input_${field}`][0].getFilterData();
      }
    },
    components: {
      SearchSelect: SearchSelect,
      PageAutocomplete: PageAutocomplete
    },
    template: template
  };
}();
